package com.dimples.dd.system.model.form;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;

import java.time.Duration;
import java.util.Date;
import java.util.List;

@Schema(description = "OAuth2 客户端创建/修改 Form")
@Data
public class OAuth2ClientForm {

    @Schema(description = "编号", example = "1024")
    private String id;

    @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "dd")
    @NotNull(message = "客户端编号不能为空")
    private String clientId;

    @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
    @NotNull(message = "客户端密钥不能为空")
    private String clientSecret;

    @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dd")
    @NotNull(message = "应用名不能为空")
    private String clientName;

    @Schema(description="客户端发布时间")
    private Date clientIdIssuedAt;

    @Schema(description="密钥有效期")
    private Date clientSecretExpiresAt;

    @Schema(description="客户端身份验证方法 (client_secret_basic/client_secret_post/client_secret_jwt)")
    private String clientAuthenticationMethods;

    @Schema(description = "授权类型，参见 AuthorizationGrantType 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "password")
    @NotNull(message = "授权类型不能为空")
    private List<String> authorizationGrantTypes;

    @Schema(description="重定向地址")
    private String redirectUris;

    @Schema(description="登出重定向地址")
    private String postLogoutRedirectUris;

    @Schema(description = "授权范围", example = "user_info")
    private List<String> scopes;

    @Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.example.cn/xx.png")
    @NotNull(message = "应用图标不能为空")
    @URL(message = "应用图标的地址不正确")
    private String clientLogo;

    @Schema(description = "应用描述", example = "我是一个应用")
    private String clientDescription;

    @Schema(description = "状态，参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @NotNull(message = "状态不能为空")
    private Integer status;

    @Schema(description = "Token 有效期（单位 s）", requiredMode = Schema.RequiredMode.REQUIRED, example = "3600")
    @NotNull(message = "Token 有效期不能为空")
    private Long accessTokenTimeToLive;

    @Schema(description = "Refresh Token 有效期（单位 s）", requiredMode = Schema.RequiredMode.REQUIRED, example = "3600")
    private Long refreshTokenTimeToLive;

    public static RegisteredClient toRegisteredClient(OAuth2ClientForm oAuth2ClientForm, PasswordEncoder passwordEncoder) {
        RegisteredClient.Builder builder = RegisteredClient.withId(oAuth2ClientForm.getId());
        if (StrUtil.isNotBlank(oAuth2ClientForm.getClientId())) {
            builder.clientId(oAuth2ClientForm.getClientId());
        }
        if (StrUtil.isNotBlank(oAuth2ClientForm.getClientName())) {
            builder.clientName(oAuth2ClientForm.getClientName());
        }
        if (StrUtil.isNotBlank(oAuth2ClientForm.getClientSecret())) {
            builder.clientSecret(passwordEncoder.encode(oAuth2ClientForm.getClientSecret()));
        }
        if (ObjectUtil.isNotEmpty(oAuth2ClientForm.getClientSecretExpiresAt())) {
            builder.clientSecretExpiresAt(oAuth2ClientForm.getClientSecretExpiresAt().toInstant());
        }
        if (StrUtil.isNotBlank(oAuth2ClientForm.getClientSecret())) {
            builder.clientSecret(oAuth2ClientForm.getClientSecret());
        }
        if (CollUtil.isNotEmpty(oAuth2ClientForm.getAuthorizationGrantTypes())) {
            builder.authorizationGrantTypes(authorizationGrantTypes -> authorizationGrantTypes.addAll(oAuth2ClientForm.getAuthorizationGrantTypes().stream().map(AuthorizationGrantType::new).toList()));
        }
        if (StrUtil.isNotBlank(oAuth2ClientForm.getRedirectUris())) {
            builder.redirectUri(oAuth2ClientForm.getRedirectUris());
        }
        if (StrUtil.isNotBlank(oAuth2ClientForm.getPostLogoutRedirectUris())) {
            builder.postLogoutRedirectUri(oAuth2ClientForm.getPostLogoutRedirectUris());
        }
        if (CollUtil.isNotEmpty(oAuth2ClientForm.getScopes())) {
            builder.scopes(val -> val.addAll(oAuth2ClientForm.getScopes()));
        }
        if (ObjectUtil.isNotEmpty(oAuth2ClientForm.getAccessTokenTimeToLive())) {
            TokenSettings.Builder tokenSettingBuilder = TokenSettings.builder()
                    .accessTokenTimeToLive(Duration.ofSeconds(oAuth2ClientForm.getAccessTokenTimeToLive()));
            if (ObjectUtil.isNotEmpty(oAuth2ClientForm.getRefreshTokenTimeToLive())) {
                tokenSettingBuilder.refreshTokenTimeToLive(Duration.ofSeconds(oAuth2ClientForm.getRefreshTokenTimeToLive()));
            }
            TokenSettings tokenSettings = tokenSettingBuilder.build();
            builder.tokenSettings(tokenSettings);
        }
        builder.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build());

        return builder.build();
    }

}
